﻿'
'   Helpers.vb
'
'   part of WHMCSdotnet (http://whmcsdotnet.wordpress.com)
'
'   Copyright (C) 2009-2011 Mark Castle <markcastle@gmail.com>
'   All rights reserved. 
'   Copyright (C) 2009-2011 Secura Hosting Ltd <code@securahosting.com>.
'   All rights reserved.
' 
'   Redistribution and use in source and binary forms, with or without modification,
'   are permitted provided that the following conditions are met:
' 
'   - Redistributions of source code must  retain  the  above copyright notice, this
'     list of conditions and the following disclaimer.
' 
'   - Redistributions in binary form  must  reproduce the  above  copyright  notice,
'     this list of conditions  and  the  following  disclaimer in  the documentation
'     and/or other materials provided with the distribution.
' 
'   - Neither  the  name  of  Secura Hosting Ltd, Mark Castle  nor the names of  its
'     contributors may be used to endorse or  promote  products  derived  from  this
'     software without specific prior written permission.
' 
'   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
'   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT  NOT  LIMITED TO, THE IMPLIED
'   WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR  PURPOSE  ARE
'   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
'   ANY DIRECT, INDIRECT, INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
'   (INCLUDING, BUT NOT LIMITED TO,  PROCUREMENT  OF  SUBSTITUTE  GOODS OR SERVICES;
'   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  HOWEVER  CAUSED AND ON
'   ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY,  OR TORT
'   (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING  IN  ANY WAY OUT OF THE USE OF THIS
'   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

' Some of this code is derived from: http://imdsm.blogspot.co.uk/2010/09/xml-to-hashtable.html
' Thank You :-)

Imports System.Xml
Namespace Secura.Xml
    Public Class Helpers

        ''' <summary>
        ''' Parse an Xml string into a Hashtable structure
        ''' </summary>
        ''' <param name="XmlString"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function ParseXml(ByVal XmlString As String) As Hashtable
            Dim xml As New XmlDocument()
            xml.LoadXml(XmlString)
            Dim root As XmlNode = xml.DocumentElement
            Return ToHashtable(root)
            xml = Nothing
        End Function

        ''' <summary>
        ''' Parse and XmlNode into a Hashtable Structure
        ''' </summary>
        ''' <param name="node"></param>
        ''' <returns></returns>
        ''' <remarks>From http://imdsm.blogspot.co.uk/2010/09/xml-to-hashtable.html With Thanks:-)</remarks>
        Public Shared Function ToHashtable(node As XmlNode) As Hashtable
            Dim ht As New Hashtable()
            ' loop through all nodes within the node
            For Each n As XmlNode In node.ChildNodes
                Dim name As String = n.Name
                Dim value As Object = Nothing

                ' if it has nodes within this node, and more than just one, then parse them
                If n.HasChildNodes Then
                    ' "In order to understand recursion, one must first understand recursion." 

                    If n.ChildNodes.Count > 1 Then
                        value = DirectCast(ToHashtable(n), Object)
                    Else
                        ' if theres only one, it may be the value, so take the value
                        If n.ChildNodes(0).NodeType = XmlNodeType.Text Then
                            value = DirectCast(n.ChildNodes(0).Value, Object)
                        Else
                            value = DirectCast(ToHashtable(n), Object)
                        End If
                    End If
                Else
                    value = DirectCast(n.Value, Object)
                End If

                ' as hashtables can't have a key the same, and xml can have two nodes of the same name
                ' we have to put the hashtables into a list if there are more than one of the same node
                ' example: <test></test> -> ht["test"] = Hashtable
                ' but: <test></test><test></test> -> ht["test"] = List<hashtable>
                If ht.ContainsKey(name) Then
                    ' list exists, add to it
                    If TypeOf ht(name) Is List(Of Hashtable) Then
                        Dim list As List(Of Hashtable) = DirectCast(ht(name), List(Of Hashtable))
                        list.Add(DirectCast(value, Hashtable))
                        ht(name) = list
                        ' list doesn't exist, so create it
                    ElseIf TypeOf ht(name) Is Hashtable Then
                        Dim list As New List(Of Hashtable)()
                        Dim htTmp As Hashtable = DirectCast(ht(name), Hashtable)
                        list.Add(htTmp)
                        list.Add(DirectCast(value, Hashtable))
                        ht(name) = list
                    End If
                Else
                    ht.Add(name, value)
                End If
            Next
            Return ht
            ' and return it
        End Function

        ''' <summary>
        ''' Recursive Function to return the Hastable as Xml
        ''' </summary>
        ''' <param name="Hash"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function HashtableToXml(ByVal Hash As Hashtable) As String
            Dim Xml As String = ""

            For Each Item In Hash
                If TypeOf (Item.Value) Is Hashtable Then
                    Xml &= String.Format("<{0}>" & _
                        HashtableToXml(Item.Value) & _
                        "</{0}>", Item.Key, Item.Value) & vbCrLf
                Else
                    If Item.Key = "#cdata-section" Then ' I think this is specific to WHMCS, need to check (TO DO)
                        Xml &= String.Format("<![CDATA[{0}]]>", Item.Value) & vbCrLf
                    Else
                        Xml &= String.Format("<{0}>{1}</{0}>", Item.Key, Item.Value) & vbCrLf
                    End If

                End If
            Next
            Return Xml
        End Function

        Public Shared Function HashtableToXmlandWrapper(ByVal Hash As Hashtable) As String
            Return "<?xml version=""1.0"" encoding=""utf-8""?>" & vbCrLf & _
                   "<whmcsapi version=""5.0.3"">" & vbCrLf & _
                   HashtableToXml(Hash)
        End Function

    End Class
End Namespace
